/*
 * Copyright (c) 2023 Cshoo Org. All Rights Reserved.
 */

package org.cshoo.tattoo.gate.handler;

import com.google.gson.Gson;
import io.jsonwebtoken.CompressionCodecs;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import io.netty.util.CharsetUtil;
import org.cshoo.tattoo.gate.entity.JwtTokenEntity;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.server.WebFilterExchange;
import org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.crypto.SecretKey;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author 杨翼
 * @since 1.0
 */
@Component
public class MyRedirectServerAuthenticationSuccessHandler extends RedirectServerAuthenticationSuccessHandler {

    @Value("${jwt.token.expiration}")
    private long tokenExpiration;

    @Value("${jwt.token.sign.key}")
    private String tokenSignKey;

    @Override
    public Mono<Void> onAuthenticationSuccess(WebFilterExchange webFilterExchange, Authentication authentication) {
        User user = (User) authentication.getPrincipal();

        List<String> authorityList = new ArrayList<>();
        user.getAuthorities().forEach(authority -> authorityList.add(authority.getAuthority()));

        byte[] keyBytes = tokenSignKey.getBytes();
        SecretKey key = Keys.hmacShaKeyFor(keyBytes);

        Gson gson = new Gson();

        long tokenExpirationTime = System.currentTimeMillis() + tokenExpiration;
        String token = Jwts.builder().setSubject(gson.toJson(user)).setHeaderParam("authorities", authorityList)
                .setExpiration(new Date(tokenExpirationTime))
                .signWith(key, SignatureAlgorithm.HS512).compressWith(CompressionCodecs.GZIP).compact();

        JwtTokenEntity jwtToken = new JwtTokenEntity();
        jwtToken.setExpirationTime(tokenExpiration);
        jwtToken.setToken(token);

        String jwtTokenString = gson.toJson(jwtToken);

        ServerHttpResponse response = webFilterExchange.getExchange().getResponse();
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        response.setStatusCode(HttpStatus.OK);
        DataBuffer buffer = response.bufferFactory().wrap(jwtTokenString.getBytes(CharsetUtil.UTF_8));

        return response.writeWith(Mono.just(buffer));
    }
}
